/*! \file buffer.c \brief Multipurpose byte buffer structure and methods. */
//*****************************************************************************
//
// File Name	: 'buffer.c'
// Title		: Multipurpose byte buffer structure and methods
// Author		: Pascal Stang - Copyright (C) 2001-2002
// Created		: 9/23/2001
// Revised		: 9/23/2001
// Version		: 1.0
// Target MCU	: any
// Editor Tabs	: 4
//
// This code is distributed under the GNU Public License
//		which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include "buffer.h"
#include <util/crc16.h>
//#include <interrupt.h>
// global variables

// initialization

void bufferInit(cBuffer* buffer, unsigned char *start, unsigned short size)
{
	// set start pointer of the buffer
	buffer->dataptr = start;
	buffer->size = size;
	// initialize index and length
	buffer->dataindex = 0;
//	buffer->writeidx = 0;
	buffer->datalength = 0;
}

// access routines
__inline__ unsigned char  bufferGetFromFront(cBuffer* buffer)
{
	unsigned char data = 0;
	
	// check to see if there's data in the buffer
	if(buffer->datalength)
	{
		// get the first character from buffer
		data = buffer->dataptr[buffer->dataindex];
		// move index down and decrement length
		buffer->dataindex = (buffer->dataindex + 1) % buffer->size;
		//if(buffer->dataindex+1 >= buffer->size)
		//{
		//	buffer->dataindex = 0;
		//}
		buffer->datalength--;
	}
	else
	{
		buffer->dataindex = 0;
	}
	// return
	return data;
}

void bufferDumpFromFront(cBuffer* buffer, unsigned short numbytes)
{
	// dump numbytes from the front of the buffer
	// are we dumping less than the entire buffer?
	if(numbytes < buffer->datalength)
	{
		// move index down by numbytes and decrement length by numbytes
		buffer->dataindex += numbytes;
		if(buffer->dataindex+1 >= buffer->size)
		{
			buffer->dataindex %= buffer->size;
		}
		buffer->datalength -= numbytes;
	}
	else
	{
		// flush the whole buffer
		buffer->datalength = 0;
	}
}

unsigned char bufferGetAtIndex(cBuffer* buffer, unsigned short index)
{
	// return character at index in buffer
	return buffer->dataptr[(buffer->dataindex+index)%(buffer->size)];
}

inline unsigned char bufferGetFirst(cBuffer* buffer)
{
	return buffer->dataptr[buffer->dataindex];
}

unsigned char bufferAddToEnd(cBuffer* buffer, unsigned char data)
{
	// make sure the buffer has room
	if(buffer->datalength < buffer->size)
	{
		// save data byte at end of buffer
		buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = data;
		// increment the length
		buffer->datalength++;
		// return success
		return 1;
	}
	else return 0;
}

void	bufferAddBufferToEndUnSafe(cBuffer* buffer, unsigned char * data, unsigned short length)
{
	unsigned char *	ptypData = data;

	// Disable interrupts
	//cli();

	do 
	{
		buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = *ptypData++;
		buffer->datalength++;
	}
	while (--length);

	// Re-anble interrupts
	//sei();

	return;
	/*unsigned short	dataEndIndex = (buffer->dataindex + buffer->datalength) % buffer->size;

	if ((dataEndIndex + length)< buffer->size)
	{	// Add to the buffer with no wrapping!
		unsigned char *pt= &buffer->dataptr[dataEndIndex];
		unsigned short i=0;
		for (;i<length;i++)
		{
			*pt++ = *data++;
		}
	}
	else
	{
		unsigned char *pt= &buffer->dataptr[dataEndIndex];
		unsigned short i=dataEndIndex;

		// End to End
		for(;i<buffer->size;i++)
		{
			*pt++ = *data++;
		}

		// Start to new end point
		pt = &buffer->dataptr[0];
		for(i=0;i<(length - (buffer->size - dataEndIndex));i++)
		{
			*pt++ = *data++;
		}
	}
		
	// Increment the Length
	buffer->datalength += length;*/
}

// Adds the data to the buffer
// and calcualtes the crc inline
// also you can specify the start crc value!
void	bufferAddBufferToEndUnSafeCrc16(cBuffer* buffer, unsigned char * data, unsigned short length, unsigned short crc)
{
	//unsigned short	dataEndIndex = (buffer->dataindex + buffer->datalength) % buffer->size;
	unsigned char *pt;
	unsigned char *	ptypData = data;
	do
	{
		pt = &buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size];
		*pt = *ptypData++;
		crc = _crc16_update(crc, *pt);
		buffer->datalength++;
	}
	while (--length);

	buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = (unsigned char)(crc >> 8);
	buffer->datalength++;
	buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = (unsigned char)(crc );
	buffer->datalength++;
	buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = 0x55;
	buffer->datalength++;
	buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = 0x5A;
	buffer->datalength++;

	return;

	/*
	if ((dataEndIndex + length)< buffer->size)
	{	// Add to the buffer with no wrapping!
		pt= &buffer->dataptr[dataEndIndex];
		unsigned short i=0;
		for (;i<length;i++)
		{
			*pt = *data++;
			crc = _crc16_update(crc, *pt++);
		}

	}
	else
	{
		pt= &buffer->dataptr[dataEndIndex];
		unsigned short i=dataEndIndex;

		// End to End
		for(;i<buffer->size;i++)
		{
			*pt = *data++;
			crc = _crc16_update(crc, *pt++);
		}

		// Start to new end point
		pt = &buffer->dataptr[0];
		for(i=0;i<(length - (buffer->size - dataEndIndex));i++)
		{
			*pt = *data++;
			crc = _crc16_update(crc, *pt++);
		}
	}

	if (dataEndIndex < (buffer->size -4))
	{
		*pt++ = (unsigned char)(crc >> 8);
		*pt++ = (unsigned char)crc;
		*pt++ = 0x55;
		*pt	  = 0x5A;

		buffer->datalength += length + 4;
	}
	else
	{
		unsigned char Foot[4] = {(unsigned char)(crc >> 8)
							,(unsigned char)crc
							,0x55
							,0x5A};

		buffer->datalength += length ;

		bufferAddBufferToEndUnSafe(buffer, Foot, 4);
	}

	// Increment the Length
	*/
}

void inline bufferAddToEndUnSafe(cBuffer* buffer, unsigned char data)
{
	buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = data;
	buffer->datalength++;
}

unsigned char bufferIsNotFull(cBuffer* buffer)
{
	// check to see if the buffer has room
	// return true if there is room
	return (buffer->datalength < buffer->size);
}

void bufferFlush(cBuffer* buffer)
{
	// flush contents of the buffer
	buffer->datalength = 0;
	buffer->dataindex = 0;
}

unsigned char	*bufferGetPtr(cBuffer* buffer)
{
	return buffer->dataptr;
}

